/** @file
@brief Platform-specific headers.

This header file is normally included first in all other Pryn headers, as it defines a number of macros for neutralising cross-platform issues (including Doxygen and C++). The following is the complete set of defined symbols that can be used, and the defines its behaviour depends upon. */


#ifndef PRYN_PLATFORM_H
#define PRYN_PLATFORM_H

// This contains documentation for fake defines within this file.
#ifdef __DOXYGEN__
/** @name User-defined
	These values can be defined before any Pryn header file is included to alter its behaviour.
	@{ */

#define PrynInternal /**< @brief This should be defined when you need to access the internal fields of base Pryn library structures. */
#define PrynImplementation /**< @brief This should only be defined when the base Pryn library is being compiled; on Windows it causes appropriate DLL functions in the headers to be exported rather than imported. */
#define PrynGuiInternal /**< @brief This should be defined when you need to access the internal fields of the Pryn GUI library structures. */
#define PrynGuiImplementation /**< @brief This should only be defined when the Pryn GUI library is being compiled; on Windows it causes appropriate DLL functions in the headers to be exported rather than imported. */
#define PrynEditorInternal /**< @brief This should be defined when you need to access the internal fields of the Pryn Editor library structures. */
#define PrynEditorImplementation /**< @brief This should only be defined when the Pryn Editor library is being compiled; on Windows it causes appropriate DLL functions in the headers to be exported rather than imported. */
#define PrynAllocationTracker /** @brief If this is defined, all allocations made by the state are tracked and can be reported on. */

/** @} */ // (group User-defined)

#define PrynBaseImport(RETURNS, NAME, ARGUMENTS) /**< @brief The base declaration macro for functions. This expands into RETURNS NAME ARGUMENTS;, inserting anything in between that's necessary, such as linkage and calling convention. */
#define PrynBaseExport(RETURNS, NAME, ARGUMENTS) /**< @brief The base definition macro for functions. This expands into RETURNS NAME ARGUMENTS, inserting anything in between that's necessary such as linkage and calling convention. */
#define PrynBaseImportVariadic(RETURNS, NAME, ARGUMENTS) /** @brief As with #PrynBaseImport, but for variadic functions (where the last argument is "..."). */
#define PrynBaseExportVariadic(RETURNS, NAME, ARGUMENTS) /** @brief As with #PrynBaseExport, but for variadic functions (where the last argument is "..."). */

#define PrynInternalStructs /**< @brief This is defined if struct declarations need to be made even for heap objects. Normally this will cause an error because all fields are hidden and C rejects empty structures. This is therefore defined if the fields will be visible, or if the language is C++. */
#define PrynImport(RETURNS, NAME, ARGUMENTS) /**< @brief The macro that should be used when declaring functions exported from the base Pryn library. Don't suffix a ';'. */
#define PrynExport(RETURNS, NAME, ARGUMENTS) /**< @brief The macro that should be used when defining functions exported from a library. */

#define PrynGuiInternalStructs /**< @brief This is defined if struct declarations need to be made even for heap objects. Normally this will cause an error because all fields are hidden and C rejects empty structures. This is therefore defined if the fields will be visible, or if the language is C++. */
#define PrynGuiImport(RETURNS, NAME, ARGUMENTS) /**< @brief The macro that should be used when declaring functions exported from the Pryn GUI library.  */
#define PrynGuiExport(RETURNS, NAME, ARGUMENTS) /**< @brief The macro that should be used when defining functions exported from the Pryn GUI library.  */

#define PrynEditorInternalStructs /**< @brief This is defined if struct declarations need to be made even for heap objects. Normally this will cause an error because all fields are hidden and C rejects empty structures. This is therefore defined if the fields will be visible, or if the language is C++. */
#define PrynEditorImport(RETURNS, NAME, ARGUMENTS) /**< @brief The macro that should be used when declaring functions exported from the Pryn GUI library.  */
#define PrynEditorExport(RETURNS, NAME, ARGUMENTS) /**< @brief The macro that should be used when defining functions exported from the Pryn GUI library.  */

typedef size_t; /**< @brief An unsigned integer that can refer to all valid pointer locations. */
typedef ssize_t; /**< @brief A signed integer that can refer to all valid pointer locations. */
typedef int32_t; /**< @brief A signed 32-bit integer. */
typedef uint32_t; /**< @brief An unsigned 32-bit integer. */
typedef int64_t; /**< @brief A signed 64-bit integer. */
typedef uint64_t; /**< @brief An unsigned 64-bit integer. */
typedef bool; /**< @brief A value that can be true or false. */
#define false /**< @brief The false boolean value. */
#define true /**< @brief A true boolean value. Don't compare to true, as in "value == true"; use "value != false" instead. */
#endif /* __DOXYGEN__ */

#include <stdarg.h>
#include <stdlib.h> // Includes size_t.

#if __cplusplus
#define PrynCDeclaration extern "C"
#define PrynCppDeclaration extern "C++"
#define PrynCSectionStart extern "C" {
#define PrynCSectionEnd }
#else
#define PrynCDeclaration
#define PrynCppDeclaration
#define PrynCSectionStart
#define PrynCSectionEnd
#endif

/* This needs to define:
	PrynBaseImport(RETURNS, NAME, ARGUMENTS)
	PrynBaseExport(RETURNS, NAME, ARGUMENTS)
	PrynBaseImportVariadic(RETURNS, NAME, ARGUMENTS)
	PrynBaseExportVariadic(RETURNS, NAME, ARGUMENTS)

	bool
	true
	false
	int32_t, uint32_t - Signed and unsigned 32-bit integers.
	int64_t, uint64_t - Signed and unsigned 64-bit integers.
*/
#ifdef _MSC_VER
	#define bool char
	#define true ((bool) 1)
	#define false ((bool) 0)

	#define PrynBaseExport(RETURNS, NAME, ARGUMENTS) __declspec (dllexport) RETURNS __stdcall NAME ARGUMENTS
	#define PrynBaseImport(RETURNS, NAME, ARGUMENTS) __declspec (dllimport) RETURNS __stdcall NAME ARGUMENTS
	#define PrynBaseExportVariadic(RETURNS, NAME, ARGUMENTS) __declspec (dllexport) RETURNS __stdcall NAME ARGUMENTS
	#define PrynBaseImportVariadic(RETURNS, NAME, ARGUMENTS) __declspec (dllimport) RETURNS __stdcall NAME ARGUMENTS

	#include <windows.h>

	typedef UINT32 uint32_t;
	typedef UINT64 uint64_t;
	typedef INT32 int32_t;
	typedef INT64 int64_t;
	typedef intptr_t ssize_t;

	#define PrynBaseLibraryEntryPoint \
		int _acrtused_dll; \
		static void __attach (void *instance); \
		\
		PrynCDeclaration int __stdcall _DllMainCRTStartup (void *instance, DWORD reason, LPVOID reserved) \
		{ \
			if (reason == DLL_PROCESS_ATTACH) \
				__attach (instance); \
			return TRUE; \
		} \
		\
		static void __attach

	#define PrynLibraryEntryPointBase() \
		PrynCDeclaration int __stdcall _DllMainCRTStartup (void *instance, int reason, void *reserved) \
		{ \
			return 1; \
		} \
		\
		int _acrtused_dll; \
		PrynCDeclaration PrynResult __declspec (dllexport) __cdecl prynLibraryInit (PrynLibrary *library)

	#define PrynLibraryEntryPointEndBase()

#elif defined(__DMC__)
	#include <stdint.h> // Includes uint8_t, intptr_t, etc.
	#if !__cplusplus
	#include <stdbool.h> // Get the bool type, and true and false.
	#endif

	#define PrynBaseExport(RETURNS, NAME, ARGUMENTS) RETURNS __declspec (dllexport) __stdcall NAME ARGUMENTS
	#define PrynBaseImport(RETURNS, NAME, ARGUMENTS) RETURNS __declspec (dllimport) __stdcall NAME ARGUMENTS
	#define PrynBaseExportVariadic(RETURNS, NAME, ARGUMENTS) RETURNS __declspec (dllexport) __pascal NAME ARGUMENTS
	#define PrynBaseImportVariadic(RETURNS, NAME, ARGUMENTS) RETURNS __declspec (dllimport) __pascal NAME ARGUMENTS

	#define PrynLibraryEntryPointBase() \
		int __stdcall DllMain (void *instance, int reason, void *reserved) \
		{ \
			return 1; \
		} \
		\
		PrynCDeclaration int _acrtused_dll; \
		PrynCDeclaration PrynResult __declspec (dllexport) __cdecl prynLibraryInit (PrynLibrary *library)

	#define PrynLibraryEntryPointEndBase()
	
	#define PrynBaseLibraryEntryPoint \
		int _acrtused_dll; \
		static void __attach (void *instance); \
		\
		int __stdcall _DllMainCRTStartup (void *instance, int reason, void *reserved) \
		{ \
			if (reason == 1) \
				__attach (instance); \
			return 1; \
		} \
		\
		static void __attach
	
	typedef uintptr_t ssize_t;

#endif /* __DMC */

#ifdef PrynImplementation
	#define PrynImport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExport (RETURNS, NAME, ARGUMENTS);
	#define PrynExport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExport (RETURNS, NAME, ARGUMENTS)
	#define PrynImportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExportVariadic (RETURNS, NAME, ARGUMENTS);
	#define PrynExportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExportVariadic (RETURNS, NAME, ARGUMENTS)
#else /* !PrynImplementation */
	#define PrynImport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseImport (RETURNS, NAME, ARGUMENTS);
	#define PrynImportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseImportVariadic (RETURNS, NAME, ARGUMENTS);
#endif /* !PrynImplementation */

#ifdef PrynGuiImplementation
	#define PrynGuiImport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExport (RETURNS, NAME, ARGUMENTS);
	#define PrynGuiExport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExport (RETURNS, NAME, ARGUMENTS)
	#define PrynGuiImportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExportVariadic (RETURNS, NAME, ARGUMENTS);
	#define PrynGuiExportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExportVariadic (RETURNS, NAME, ARGUMENTS)
#else /* !PrynGuiImplementation */
	#define PrynGuiImport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseImport (RETURNS, NAME, ARGUMENTS);
	#define PrynGuiImportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseImportVariadic (RETURNS, NAME, ARGUMENTS);
#endif /* !PrynImplementation */

#ifdef PrynEditorImplementation
	#define PrynEditorImport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExport (RETURNS, NAME, ARGUMENTS);
	#define PrynEditorExport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExport (RETURNS, NAME, ARGUMENTS)
	#define PrynEditorImportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExportVariadic (RETURNS, NAME, ARGUMENTS);
	#define PrynEditorExportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseExportVariadic (RETURNS, NAME, ARGUMENTS)
#else /* !PrynEditorImplementation */
	#define PrynEditorImport(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseImport (RETURNS, NAME, ARGUMENTS);
	#define PrynEditorImportVariadic(RETURNS, NAME, ARGUMENTS) PrynCDeclaration PrynBaseImportVariadic (RETURNS, NAME, ARGUMENTS);
#endif /* !PrynImplementation */

#if defined (PrynGuiInternal) || defined (__DOXYGEN__) || __cplusplus
	#define PrynGuiInternalStructs 1
#endif

#if defined (PrynEditorInternal) || defined (__DOXYGEN__) || __cplusplus
	#define PrynEditorInternalStructs 1
#endif

#if defined (PrynInternal) || defined (__DOXYGEN__) || __cplusplus
	#define PrynInternalStructs 1
#endif

#if __cplusplus
	#define PrynLibraryEntryPoint() \
		PrynLibraryEntryPointBase () \
		{ \
			try \
			{

	#define PrynLibraryEntryPointEnd() \
			} \
			catch (PrynException &exception) \
			{ \
				return exception.result; \
			} \
			return PrynResultSuccess; \
		} \
		PrynLibraryEntryPointEndBase ()

#else /* !__cplusplus */
#define PrynLibraryEntryPoint() PrynLibraryEntryPointBase ()
#define PrynLibraryEntryPointEnd() PrynLibraryEntryPoinEndBase ()
#endif /* !__cplusplus */

/*#if __cplusplus
extern "C" {
#endif

#if __cplusplus
}
#endif*/

#include <pryn/common.h>

#endif /* PRYN_PLATFORM_H */
